
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.LinkedHashMap;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 数字验签
 * 
 * @author rocker
 * 
 */
public class SignHelper {

	private final static Log log = LogFactory.getLog(SignHelper.class);
	public final static String encoding = "UTF-8";

	public static void main(String[] args) throws Exception {
		testPayNotify();
	}

	/**
	 * 测试支付通知
	 * 
	 * @return
	 */
	public static void testPayNotify() throws Exception {
		Map<String, String> para = new LinkedHashMap<String, String>();
		para.put("send_type", "2");
		para.put("simid", "460000013597859");
		para.put("imei", "863034013198648");
		para.put("phone", "13850011182");
		para.put("operator", "1");
		para.put("province", "9");
		para.put("city", "911");
		para.put("serial", "SHQJ_QLDDZ_A01");
		para.put("svn", "AND_PAY_V_1_0_6");
		para.put("price", "2");
		para.put("os_id", "6cb7d4a4a41cf3d4");
		para.put("os_type", "1");
		para.put("cp_id", "102");
		para.put("cp_user_id", "");
		para.put("cp_param", "265675,10000");
		para.put("pay_guid", "102131129000253348268783");
		para.put("pay_type", "1");
		para.put("pay_price", "2");
		para.put("pay_status", "1");
		para.put("pay_item_id", "2002");
		para.put("pay_item_name", "游戏内充值");
		para.put("pay_time", "2013-11-29 00:02:53");
		para.put("las_time", "2013-11-29 00:03:23");
		String plainText = JSONObject.fromObject(para).toString();
		System.out.println(plainText);
		PropertiesConfiguration propConfig = new PropertiesConfiguration(System.getProperty("user.dir") + "/conf/environment.properties");
		String pubKeyStr = propConfig.getString("payNotify.pubKey");
		String signStr = "YqkBFnCtYi/KBBul8vJyN69bGQ0O1dh6UUsr3XXHNV7fql+lxWQ9JZKW+JkpcUOWDVBchsLaGu/sfQPp8jrbhRNnOwzGG3EJkyC2Kkc9Bqa0F5e1iaa9Kq7XARcqR/KFmOT7atrhysef1Upg/1RX1iGzW3rNeQNu18m15yRjDLRHsywpMze3Lp4vtJ/TmFn/XvSnLs/3xV3LSH3Blb958Fnd+//YTz2lnY5DWWFFvr1FMN5TXJVWYeUPtQAiAvprhTd2G7pMNCpxghfPmdkZEbNXhp0NFXcSiLchLuTWwJKWrVK4+BETd5CXhqvjzu5XlnT5iY4DtV5ut8RpxlWAHA==";
		byte[] sign = signStr.getBytes(encoding);
		para.put("sign", new String(sign, encoding));
		String body = JSONObject.fromObject(para).toString();
		JSONObject jsonBean = JSONObject.fromObject(body);
		@SuppressWarnings("unchecked")
		Map<String, String> rmap = (Map<String, String>) JSONObject.toBean(jsonBean, LinkedHashMap.class);
		String sig = rmap.get("sign");
		sign = sig.getBytes(encoding);
		rmap.remove("sign");
		plainText = JSONObject.fromObject(rmap).toString();
		boolean verify = verify(plainText, sign, pubKeyStr);
		if (verify)
			System.out.println("验签成功！");
		else
			System.out.println("验签失败！");
	}

	/**
	 * 得到密钥字符串(经过base64编码)
	 * 
	 * @return
	 */
	public static String getKeyString(Key key) throws Exception {
		byte[] keyBytes = key.getEncoded();
		String keyStr = new String(Base64.encodeBase64(keyBytes), encoding);
		return keyStr;
	}

	/**
	 * 获得公钥
	 * 
	 * @param key
	 *            : 密钥字符串(经过base64编码)
	 */
	public static PublicKey getPublicKey(String key) throws Exception {
		byte[] keyBytes = Base64.decodeBase64(key.getBytes(encoding));
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	/**
	 * 获得私钥
	 * 
	 * @param key
	 *            : 密钥字符串(经过base64编码)
	 */
	public static PrivateKey getPrivateKey(String key) throws Exception {
		byte[] keyBytes = Base64.decodeBase64(key.getBytes(encoding));
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}

	/**
	 * 获得签名数据
	 * 
	 * @param plainText
	 *            : 原文
	 * @param priKeyStr
	 *            : 私钥
	 * @return
	 */
	public static byte[] getSign(String plainText, String priKeyStr) throws Exception {
		PrivateKey privateKey = getPrivateKey(priKeyStr);
		/** 数字签名 **/
		Signature signature = Signature.getInstance("SHA1withRSA");
		/** 用自己的私钥对数据签名 **/
		signature.initSign(privateKey);
		signature.update(plainText.getBytes(encoding));
		byte[] signByte = signature.sign();
		return Base64.encodeBase64(signByte);
	}

	/**
	 * 验签
	 * 
	 * @param plainText
	 *            : 原文
	 * @param sign
	 *            : 签名数据
	 * @param pubKeyStr
	 *            : 公钥
	 * @return
	 */
	public static boolean verify(String plainText, byte[] sign, String pubKeyStr) {
		boolean verify = false;
		try {
			PublicKey publicKey = getPublicKey(pubKeyStr);
			Signature signature = Signature.getInstance("SHA1withRSA");
			/** 比较两次数据结果是否一致 **/
			signature.initVerify(publicKey);
			signature.update(plainText.getBytes(encoding));
			verify = signature.verify(Base64.decodeBase64(sign));
		} catch (Exception e) {
			log.error("sign verify error.", e);
		}
		return verify;
	}
}
